/* 网络通信模块 */

#include "UserManager.hpp"
#include "MsgQueue.hpp"
#include <unistd.h>
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <pthread.h>
#include <string.h>

#define PORT 28989
#define THREADCOUNT 4 
#define TCP_DATA_MAX 65535

/*【for rest】 recv_send 队列的数据结构 */
struct Msg
{
    Msg()
    {
        _sockfd = -1;
        memset(_buf, '\0', sizeof(_buf));
    }

    int _sockfd;
    char _buf[1024];
};

class ChatServer
{
public:
    ChatServer()
        : _tcp_sockfd(-1)
        , _tcp_port(PORT)
        , _epoll_fd(-1)
        , _user_mana(NULL)
        , _thread_count(THREADCOUNT)
        , _ready_sockfd_que(NULL)
        , _send_que(NULL)
    {}

    ~ChatServer(){}

    // 1.初始化资源接口
    int InitChatServer(uint16_t tcp_port = PORT, int thread_count = THREADCOUNT)
    {
        _tcp_port = tcp_port;
        _thread_count = thread_count;

        /* tcp通信 */
        _tcp_sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_tcp_sockfd < 0)
        {
            perror("socket");
            return -1;
        }
        
        // 端口重用--防止服务端在time_wait状态重启
        int opt = 1;
        setsockopt(_tcp_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

        struct sockaddr_in ser_addr;
        ser_addr.sin_family = AF_INET;
        ser_addr.sin_port = htons(_tcp_port);
        ser_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
        int ret = bind(_tcp_sockfd, (struct sockaddr*)&ser_addr, sizeof(ser_addr));    //绑定
        if(ret < 0)
        {
            perror("bind");
            return -1;
        }
        
        ret = listen(_tcp_sockfd, 1024);    //监听
        if(ret < 0)
        {
            perror("listen");
            return -1;
        }

        // epoll初始化
        _epoll_fd = epoll_create(3);
        if(_epoll_fd < 0)
        {
            perror("epoll_create");
            return -1;
        }

        /* 用户管理模块 */
        _user_mana = new UserManager();
        if(_user_mana == NULL)
        {
            return -1;
        }
        if(_user_mana->InitUserManager() == false)
        {
            return -1;
        }

        /* 队列模块 */
        _ready_sockfd_que = new MsgQueue<int>();
        if(_ready_sockfd_que == NULL)
        {
            return -1;
        }

        _send_que = new MsgQueue<Msg>();
        if(_send_que == NULL)
        {
            return -1;
        }
        
        return 0;
    }

    // 2.启动子线程接口（main函数调用启动）
    int StartChatServer()
    {
        // 1)创建epoll_wait线程
        pthread_t tid; 
        int ret = pthread_create(&tid, NULL, epoll_wait_start, (void*)this);
        if(ret < 0)
        {
            perror("pthread_create epoll_wait()");
            return -1;
        }

#if 1
        // 2)创建接收线程
        ret = pthread_create(&tid, NULL, recv_msg_start, (void*)this);
        if(ret < 0)
        {
            perror("pthread_create recv_msg_start()");
            return -1;
        }
#endif

        // 3)创建发送线程
        ret = pthread_create(&tid, NULL, send_msg_start, (void*)this);
        if(ret < 0)
        {
            perror("pthread_create send_msg_start()");
            return -1;
        }

        // 4)创建工作线程
        

        // 5)主线程循环accept新连接
        struct sockaddr_in cli_addr;
        socklen_t cli_addr_len = sizeof(cli_addr);
        while(1)
        {
            int new_sockfd = accept(_tcp_sockfd, (struct sockaddr*)&cli_addr, &cli_addr_len);    //接收新连接套接字
            if(new_sockfd < 0)
            {
                continue;
            }

            struct epoll_event ee;
            ee.events = EPOLLIN;
            ee.data.fd = new_sockfd;
            epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, new_sockfd, &ee);    //添加新连接套接字至epoll监控
        }
        return 0;
    }

    // 3.epoll_wait线程启动函数
    static void* epoll_wait_start(void* arg)
    {
        pthread_detach(pthread_self());    //线程分离
        ChatServer* cs = (ChatServer*)arg;

        while(1)
        {
            struct epoll_event ee_arr[10];
            int ret = epoll_wait(cs->_epoll_fd, ee_arr, sizeof(ee_arr)/sizeof(ee_arr[0]), -1);    //循环epoll_wait
            if(ret < 0)
            {
                continue;
            }

            for(int i = 0; i < ret; ++i)    //添加epoll捕获的事件（epoll只监听了new_socket）
            {
#if 1
                cs->_ready_sockfd_que->push(ee_arr[i].data.fd);
                /*
                 *【测试】
                 * 一个客户端发送一个消息，服务端成功接受，但输出的_ready_sockfd_que已存在9999（max）个事件套接字（均为该客户端的new_sockfd）
                 *【分析】
                 * epoll捕获一个事件后，只进行push，epoll并不会认为该事件被处理
                 * 对于LT（水平触发）的epoll来说，会不断重复通知该事件 ==> 进而导致一个客户端发出一个事件即会使_ready_sockfd_que填满
                 * */
#endif

#if 0
                //char buf[TCP_DATA_MAX] = {0};
                Msg msg;
                msg._sockfd = ee_arr[i].data.fd;
                
                //【注】TCP粘包问题
                
                ssize_t recv_size = recv(ee_arr[i].data.fd, msg._buf, sizeof(msg._buf)-1, 0);    //接收new_socket
                if(recv_size < 0)    //接受失败
                {
                    std::cout << "recv faild, sockfd is " << ee_arr[i].data.fd << std::endl;
                    continue;
                }
                else if(recv_size == 0)    //对端关闭
                {
                    epoll_ctl(cs->_epoll_fd, EPOLL_CTL_DEL, ee_arr[i].data.fd, NULL);    //剔除epoll监控
                    close(ee_arr[i].data.fd);    //关闭该套接字
                    continue;
                }

                // 正常recv
                printf("epoll_wait resv socket[%d]:%s\n", ee_arr[i].data.fd, msg._buf);    //for test
                // 添加Msg至消息队列
                cs->_send_que->push(msg);
#endif
            }
        }
        return NULL;
    }

    // 4.接收线程启动函数————！！有问题！！
    static void* recv_msg_start(void* arg)
    {
        pthread_detach(pthread_self());    //线程分离
        ChatServer* cs = (ChatServer*)arg;

        while(1)
        {
            // 从就绪队列获取new_sockfd
            int sockfd = -1;
            cs->_ready_sockfd_que->pop(&sockfd);

            //char buf[TCP_DATA_MAX] = {0};
            Msg msg;
            msg._sockfd = sockfd;

            ssize_t recv_size = recv(sockfd, msg._buf, sizeof(msg._buf)-1, 0);    //接收new_socket
            if(recv_size < 0)    //接受失败
            {
                std::cout << "recv faild, sockfd is " << sockfd << std::endl;
                continue;
            }
            else if(recv_size == 0)    //对端关闭
            {
                epoll_ctl(cs->_epoll_fd, EPOLL_CTL_DEL,sockfd, NULL);    //剔除epoll监控
                close(sockfd);    //关闭该套接字
                continue;
            }

            // 正常recv
            printf("epoll_wait resv socket[%d]:%s\n", sockfd, msg._buf);    //for test
            // 添加Msg至消息队列
            cs->_send_que->push(msg);
            
            std::cout << "_ready_sockfd_que count: " << cs->_ready_sockfd_que->GetQueValueCount()  << std::endl;
        }
        
        return NULL;
    }
    
    // 5.发送线程启动函数
    static void* send_msg_start(void* arg)
    {
        pthread_detach(pthread_self());    //线程分离
        ChatServer* cs = (ChatServer*)arg;
        
        while(1)
        {
            Msg msg;
            cs->_send_que->pop(&msg);    //获取队列数据
            int ret = send(msg._sockfd, msg._buf, strlen(msg._buf), 0);    //发送数据
            if(ret < 0)
            {
                perror("send");
                continue;
            }
        }
        return NULL;
    }
    
    // 6.工作线程启动函数
    static void* deal_start(void* arg)
    {
        pthread_detach(pthread_self());    //线程分离
        ChatServer* cs = (ChatServer*)arg;
        
        return NULL;
    }

private:
    /* tcp通信模块 */
    int _tcp_sockfd;    //侦听套接字
    int _tcp_port;      //端口
    
    int _epoll_fd;      //epoll操作句柄

    /* 用户管理模块 */
    UserManager* _user_mana;

    /* 工作线程模块 */
    int _thread_count;  //工作线程数量

    /* 消息队列模块 */
    Msg _msg;
    MsgQueue<int>* _ready_sockfd_que;    //就绪文件描述符队列  //接收线程队列
    MsgQueue<Msg>* _send_que;    //发送线程队列（存放recv数据）
};
